package com.love.marriage.filter;

import com.alibaba.fastjson.JSONObject;
import com.love.marriage.common.interfaces.avoid.LogRestRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringJoiner;

/**
 * 日志打印切面
 *
 * @author <a href="mailto:hongcq@emrubik.com">hongcq</a>
 * @version 1.0 $ 2024/12/11 14:41
 */
@Aspect
@Component
@Order(1)
public class RestRequestLogAop {

    /**
     * LOG
     */
    private final Logger log = LoggerFactory.getLogger(getClass());

    @Before("@annotation(logRestRequest)")
    public void logRestRequest(JoinPoint joinPoint, LogRestRequest logRestRequest) {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                    .getRequestAttributes();
            if (attributes == null) {
                return;
            }
            HttpServletRequest request = attributes.getRequest();
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            // 获取方法参数列表及其实例值
            String[] methodParameters = signature.getParameterNames();
            Object[] args = joinPoint.getArgs();
            // 过滤掉 HttpServletRequest 类型的参数
            List<String> filteredParameters = new ArrayList<>();
            List<Object> filteredArgs = new ArrayList<>();
            for (int i = 0; i < methodParameters.length; i++) {
                if (!(args[i] instanceof HttpServletRequest)) {
                    filteredParameters.add(methodParameters[i]);
                    filteredArgs.add(args[i]);
                }
            }
            // 构建参数字符串
            String parametersStr = buildParametersString(filteredParameters.toArray(new String[0]), filteredArgs.toArray(), logRestRequest.parameters());
            log.info("收到{}接口请求, URL: [{} {}] 参数为：[{}]", logRestRequest.apiName(), request.getMethod(),
                    request.getRequestURI(), parametersStr);
        } catch (Throwable t) {
            log.error("打印日志异常", t);
        }
    }

    /**
     * 构建参数字符串
     *
     * @param methodParameters
     *            方法参数名
     * @param args
     *            方法参数值
     * @param specifiedParameters
     *            指定打印的参数名
     * @return 参数字符串
     */
    private String buildParametersString(String[] methodParameters, Object[] args, String[] specifiedParameters) {
        StringJoiner parameterJoiner = new StringJoiner(", ");
        if (specifiedParameters.length == 0) {
            // 打印所有参数
            for (int i = 0; i < methodParameters.length; i++) {
                parameterJoiner.add(methodParameters[i] + ": " + formatValue(args[i]));
            }
        } else {
            // 打印指定参数
            for (int i = 0; i < methodParameters.length; i++) {
                if (Arrays.asList(specifiedParameters).contains(methodParameters[i])) {
                    parameterJoiner.add(methodParameters[i] + ": " + formatValue(args[i]));
                }
            }
        }
        return parameterJoiner.toString();
    }

    /**
     * 格式化参数值，将数组转换为字符串
     *
     * @param value
     *            参数值
     * @return 格式化后的参数值
     */
    private String formatValue(Object value) {
        if (value == null) {
            return null;
        }
        
        // 特殊处理 MultipartFile 类型，避免序列化异常
        if (value instanceof MultipartFile) {
            MultipartFile file = (MultipartFile) value;
            return String.format("MultipartFile{name='%s', originalFilename='%s', size=%d, contentType='%s'}",
                    file.getName(), file.getOriginalFilename(), file.getSize(), file.getContentType());
        }
        
        if (value.getClass().isArray()) {
            int length = Array.getLength(value);
            StringBuilder sb = new StringBuilder("[");
            for (int i = 0; i < length; i++) {
                sb.append(formatValue(Array.get(value, i)));
                if (i < length - 1) {
                    sb.append(", ");
                }
            }
            sb.append("]");
            return sb.toString();
        }
        
        try {
            return JSONObject.toJSONString(value);
        } catch (Exception e) {
            // 如果序列化失败，返回对象的 toString()
            return value.toString();
        }
    }
}

